
// 解析表达式
#include <stdlib.h>
#include "alloc.h"
#include "input.h"
#include "str.h"
#include "lex.h"
#include "expr.h"
#define LOG_TAG "Expression"
#include "log.h"

static AstDeclaration ParseTypeDeclaration(void);

/**
LiteralExpression :
    Identifier
    IntegerLiteral
    FloatLiteral
    小括号表达式
    大括号语句
 */
static AstLiteral ParseLiteral(void)
{
    AstLiteral expr;
    switch (Token) {
    case TK_ID:
    case TK_INTEGER:
    case TK_FLOAT:
    case TK_PAREN:
    case TK_BRACE:
        CREATE_AST_NODE(expr, Literal);
        expr->tk = Token;
        expr->val = TokenStart;
        expr->valLen = TokenLen;
        NextToken();
        break;

    default:
        Error("Expect identifier, number, (...), {...}");
        exit(EXT_NotExpect);
    }
    return expr;
}

static LiteralValue ParseLiteralValue(int askTk)
{
    if (askTk != Token) {
        Error("Expect %s", TokenStrings[askTk]);
        exit(EXT_NotExpect);
    }

    LiteralValue val;
    switch (Token) {
    case TK_ID:
        val.s = InternName(TokenStart, TokenLen);
        break;
    case TK_INTEGER:
        val.i = (int) strtol(TokenStart, NULL, 0);
        break;
    case TK_FLOAT:
        val.f = strtod(TokenStart, NULL);
        break;

    default:
        Error("Expect identifier, number");
        exit(EXT_NotExpect);
    }
    NextToken();
    return val;
}

static AstLabel ParseLabel()
{
    AstLabel lab;
    CREATE_AST_NODE(lab, Label);
    lab->name = ParseLiteralValue(TK_ID).s;
    return lab;
}

/**
TypeQualifier :
    无
    sign
    unsign
    big
    little
    align ( IntegerLiteral )
    size ( IntegerLiteral )
    len ( 小括号表达式 )
    pos ( 小括号表达式 )
    when ( 小括号表达式 )
    encode ( 小括号表达式 )
    decode ( 小括号表达式 )
    print ( 小括号表达式 )
    export ( Identifier )
 */
static AstTypeQualifier ParseTypeQualifier(void)
{
    AstTypeQualifier expr;
    CREATE_AST_NODE(expr, TypeQualifier);
    int count = 0;

    while (Token != TK_END) {
        switch (Token) {
        case TK_SIGN:
            NextToken();
            expr->sign = TQ_SIGN;
            break;
        case TK_UNSIGN:
            NextToken();
            expr->sign = TQ_UNSIGN;
            break;
        case TK_BIG:
            NextToken();
            expr->sort = TQ_BIG;
            break;
        case TK_LITTLE:
            NextToken();
            expr->sort = TQ_LITTLE;
            break;

        case TK_ALIGN:
            NextToken();
            Expect(TK_LPAREN);
            expr->align = ParseLiteralValue(TK_INTEGER).i;
            Expect(TK_RPAREN);
            break;
        case TK_SIZE:
            NextToken();
            Expect(TK_LPAREN);
            expr->size = ParseLiteralValue(TK_INTEGER).i;
            Expect(TK_RPAREN);
            break;

        case TK_LEN:
            NextToken();
            ScanParen();
            expr->len = ParseLiteral();
            break;
        case TK_POS:
            NextToken();
            ScanParen();
            expr->pos = ParseLiteral();
            break;
        case TK_WHEN:
            NextToken();
            ScanParen();
            expr->when = ParseLiteral();
            break;
        case TK_ENCODE:
            NextToken();
            ScanParen();
            expr->encode = ParseLiteral();
            break;
        case TK_DECODE:
            NextToken();
            ScanParen();
            expr->decode = ParseLiteral();
            break;
        case TK_PRINT:
            NextToken();
            ScanParen();
            expr->print = ParseLiteral();
            break;
        case TK_EXPORT:
            NextToken();
            Expect(TK_LPAREN);
            expr->export = ParseLiteralValue(TK_ID).s;
            Expect(TK_RPAREN);
            break;
        default:
            return (count > 0) ? expr : NULL;
        }
        count++;
    }
    return expr;
}

/**
EnumFieldSpecifier :
    enum { EnumDeclarationList }
    field { EnumDeclarationList }
EnumDeclarationList :
    EnumDeclaration , EnumDeclarationList
    EnumDeclaration
EnumDeclaration :
    Identifier ( IntegerLiteral )
 */
static AstExpression ParseEnumFieldSpecifier(void)
{
    AstExpression expr;
    CREATE_AST_NODE(expr, Expression);
    expr->tk = Token;
    AstNode *p = &expr->kids[1];
    NextToken();

    int val = 0;
    AstEnumDeclaration item;

    Expect(TK_LBRACE);
    while (Token != TK_END) {
        CREATE_AST_NODE(item, EnumDeclaration);
        item->name = ParseLiteralValue(TK_ID).s;
        if (Token == TK_LPAREN) {
            NextToken();
            val = ParseLiteralValue(TK_INTEGER).i;
            Expect(TK_RPAREN);
        }
        item->val = val++;

        *p = (AstNode) item;
        p = &item->next;

        if (Token == TK_RBRACE) break;
        Expect(TK_COMMA);
    }
    Expect(TK_RBRACE);
    return expr;
}

/**
StructSpecifier :
    struct { DeclarationExpressionopt }
 */
static AstExpression ParseStructSpecifier(void)
{
    AstExpression expr;
    CREATE_AST_NODE(expr, Expression);
    expr->tk = TK_STRUCT;
    AstNode *p = &expr->kids[1];
    Expect(TK_STRUCT);

    Expect(TK_LBRACE);
    while (Token != TK_END && Token != TK_RBRACE) {
        *p = (AstNode) ParseTypeDeclaration();
        p = &(*p)->next;
    }
    Expect(TK_RBRACE);
    return expr;
}

/**
ChoseSpecifier :
    chose ( 小括号表达式 ) { ChoseDeclarationopt }
ChoseDeclaration :
    IntegerLiteral : DeclarationExpression
 */
static AstExpression ParseChoseSpecifier(void)
{
    AstExpression expr;
    CREATE_AST_NODE(expr, Expression);
    expr->tk = TK_CHOSE;
    AstNode *p = &expr->kids[1];

    Expect(TK_CHOSE);
    ScanParen();
    expr->kids[0] = (AstNode) ParseLiteral();

    AstChoseDeclaration item;

    Expect(TK_LBRACE);
    while (Token != TK_END && Token != TK_RBRACE) {
        CREATE_AST_NODE(item, ChoseDeclaration);
        if (Token == TK_INTEGER) {
            item->val = ParseLiteralValue(TK_INTEGER).i;
        } else {
            item->isDefault = 1;
        }
        Expect(TK_COLON);
        item->expr = (AstNode) ParseTypeDeclaration();

        *p = (AstNode) item;
        p = &item->next;
    }
    Expect(TK_RBRACE);
    return expr;
}

static int GetNumberBaseType(int size, int align, int sign)
{
    if (size == 1 && align == 0) {
        return BT_Bit;
    } else if (size == 8 && align == 1) {
        if (sign == TQ_SIGN) return BT_SChar;
        else return BT_UChar;
    } else if (size == 16 && align == 2) {
        if (sign == TQ_SIGN) return BT_SShort;
        else return BT_UShort;
    } else if (size == 32 && align == 4) {
        if (sign == TQ_SIGN) return BT_SInt;
        else return BT_UInt;
    } else if (size == 64 && align == 8) {
        if (sign == TQ_SIGN) return BT_SLong;
        else return BT_ULong;
    }

    if (size <= 0) {
        // 默认为32位无符号类型
        return BT_UnAlign | BT_UInt;
    } else if (size <= 8) {
        if (sign == TQ_SIGN) return BT_UnAlign | BT_SChar;
        else return BT_UnAlign | BT_UChar;
    } else if (size <= 16) {
        if (sign == TQ_SIGN) return BT_UnAlign | BT_SShort;
        else return BT_UnAlign | BT_UShort;
    } else if (size <= 32) {
        if (sign == TQ_SIGN) return BT_UnAlign | BT_SInt;
        else return BT_UnAlign | BT_UInt;
    } else if (size <= 64) {
        if (sign == TQ_SIGN) return BT_UnAlign | BT_SLong;
        else return BT_UnAlign | BT_ULong;
    }

    Error("Number type up to 64 bits, %d is too big", size);
    return BT_UnAlign | BT_ULong;
}

static int GetDecimalBaseType(int size, int align)
{
    if (size == 32) {
        if (align == 4) return BT_Float;
        else return BT_UnAlign | BT_Float;
    } else if (size == 64) {
        if (align == 8) return BT_Double;
        else return BT_UnAlign | BT_Double;
    }

    Error("Decimal type require 32 or 64 bits, %d bits not support", size);
    return BT_UnAlign | BT_Double;
}

/**
DeclarationExpression
    TypeDeclaration ;
    TypeDeclaration ArraySpecifier ;
TypeDeclaration :
    TypeQualifieropt TypeSpecifier Identifier
TypeSpecifier :
    NumberSpecifier
    DecimalSpecifier
    EnumFieldSpecifier
    StructSpecifier
    ChoseSpecifier
    Identifier
ArraySpecifier
    [ ]
    [ IntegerLiteral ]
    [ Identifier ]
    [ ( 小括号表达式 ) ]
 */
static AstDeclaration ParseTypeDeclaration(void)
{
    AstDeclaration decl;
    CREATE_AST_NODE(decl, Declaration);
    decl->ql = ParseTypeQualifier();

    switch (Token) {
    case TK_NUM:
    case TK_DECIMAL: {
            AstExpression type;
            CREATE_AST_NODE(type, Expression);
            type->tk = Token;
            decl->type = (AstNode) type;
        }
        if (decl->ql == NULL) {
            // 默认为32位无符号类型
            decl->baseType = (Token == TK_NUM) ? BT_UInt : BT_Float;
            decl->baseType |= BT_UnAlign;
        } else if (Token == TK_NUM) {
            decl->baseType = GetNumberBaseType(decl->ql->size, decl->ql->align, decl->ql->sign);
        } else {
            decl->baseType = GetDecimalBaseType(decl->ql->size, decl->ql->align);
        }
        NextToken();
        break;
    case TK_ENUM:
    case TK_FIELD:
        decl->type = (AstNode) ParseEnumFieldSpecifier();
        if (decl->ql == NULL) {
            decl->baseType = BT_UnAlign | BT_UInt;
            break;
        }
        decl->baseType = GetNumberBaseType(decl->ql->size, decl->ql->align, decl->ql->sign);
        break;
    case TK_STRUCT:
        decl->type = (AstNode) ParseStructSpecifier();
        decl->baseType = BT_Struct;
        break;
    case TK_CHOSE:
        decl->type = (AstNode) ParseChoseSpecifier();
        decl->baseType = BT_Union;
        break;
    case TK_ID:
        decl->type = (AstNode) ParseLabel();
        decl->baseType = BT_Typedef;
        break;
    default:
        Error("Expect num, decimal, enum, field, struct, chose, identifier");
        exit(EXT_NotExpect);
    }

    decl->name = ParseLiteralValue(TK_ID).s;

    if (Token == TK_LBRACKET) {
        NextToken();
        if (Token == TK_LPAREN) {
            ScanParen();
            decl->array = ParseLiteral();
            decl->baseType |= BT_DynArray;
        } else if (Token == TK_ID) {
            decl->array = ParseLiteral();
            decl->baseType |= BT_DynArray;
        } else if (Token == TK_INTEGER) {
            decl->array = ParseLiteral();
            decl->baseType |= BT_StaticArray;
        } else {
            decl->baseType |= BT_DynArray;
        }
        Expect(TK_RBRACKET);
    }
    Expect(TK_SEMICOLON);
    return decl;
}

/**
TypedefExpression :
    typedef Declaration
*/
static AstExpression ParseTypedefExpression(void)
{
    AstExpression type;
    CREATE_AST_NODE(type, Expression);
    type->tk = TK_TYPEDEF;
    Expect(TK_TYPEDEF);
    AstDeclaration base = ParseTypeDeclaration();
    base->funcName = base->name;
    type->kids[0] = (AstNode) base;
    return type;
}

/**
ImportExpression :
    import ( 小括号表达式 )
*/
static AstExpression ParseImportExpression(void)
{
    AstExpression expr;
    CREATE_AST_NODE(expr, Expression);
    expr->tk = TK_IMPORT;
    Expect(TK_IMPORT);
    ScanParen();
    expr->kids[0] = (AstNode) ParseLiteral();
    return expr;
}

/**
CompileExpression :
    compile { 大括号语句 }
*/
static AstExpression ParseCompileExpression(void)
{
    AstExpression expr;
    CREATE_AST_NODE(expr, Expression);
    expr->tk = TK_COMPILE;
    Expect(TK_COMPILE);
    ScanBrace();
    expr->kids[0] = (AstNode) ParseLiteral();
    return expr;
}

/**
SourceFile :
    Expressionopt
Expression :
    ImportExpression
    CompileExpression
    TypedefExpression
    DeclarationExpression
 */
AstNode ParseSourceFile(void)
{
    AstNode expr;
    AstNode *p = &expr;
    while(Token != TK_END) {
        switch (Token) {
        case TK_TYPEDEF:
            *p = (AstNode) ParseTypedefExpression();
            break;
        case TK_IMPORT:
            *p = (AstNode) ParseImportExpression();
            break;
        case TK_COMPILE:
            *p = (AstNode) ParseCompileExpression();
            break;
        default:
            *p = (AstNode) ParseTypeDeclaration();
            break;
        }
        p = &(*p)->next;
    }
    return expr;
}
